package facilitator;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import util.Util;

import core.CalculationException;
import core.DmuList;
import core.Optimizer;
import core.PdmOptimization;

public class TransitionExplorer {
	private List<StoreItem> store;
	private DmuList dmuList;
	private double[] urmWeights;
	private int[] optimizationDirections;
	
	
	public TransitionExplorer(DmuList dmuList, double[] urmWeights, int[] optimizationDirections) {
		super();
		this.optimizationDirections = optimizationDirections;
		this.dmuList = dmuList;
		this.urmWeights = urmWeights;
		this.store = new ArrayList<StoreItem>();
	}
	public List<PdmOptimization> getTransitionList() throws CalculationException{
		this.fillStore();		
		Collections.sort(store);
		List<PdmOptimization> transitionlist = new ArrayList<PdmOptimization>(); 
		double lastsize = store.get(0).pdmOptimization.getProfileDistance();
		transitionlist.add(store.get(0).pdmOptimization);
		for(int i = 0; i<store.size();i++){
			if(Util.roundUp(store.get(i).pdmOptimization.getProfileDistance(), 8) != Util.roundUp(lastsize, 8)){
				lastsize = store.get(i).pdmOptimization.getProfileDistance();
				transitionlist.add(store.get(i).pdmOptimization);
			}
		}
		Collections.sort(transitionlist);
		return transitionlist;
	}
	private StoreItem findNextTransition(double lastflaeche, double nextbase) throws CalculationException{
		StoreItem nextBaseItem;
		double step = 0.05;
		double currentflaeche = lastflaeche;
		PdmOptimization temp = null;
		
		//iterate using step until new flaeche is reached
		int u = 1;
		while(lastflaeche == currentflaeche && u < 10){
			//Util.print("while "  + u++ + " base " + nextbase);
			nextbase += step;
			temp = store(nextbase);
			currentflaeche = temp.getProfileDistance();
			u++;
		}
		//print("NewBase: " + nextbase + "\t" + currentflaeche);
		nextBaseItem = new StoreItem(nextbase, temp);
		lastflaeche = currentflaeche;
		
		boolean direction = false; //direction indicator: false is down, true is up
		nextbase = nextbase-step/2;
		//print("a " + nextbase);
		if(store(nextbase).getProfileDistance() == lastflaeche){
			direction = false;
		}
		else{
			direction = true;
		}		
		double smallstep = step/4;
		double lastround = currentflaeche;
		//print("lastround " + lastround);
		for (int i =0;i <30;i++){
			//Util.print("Loop "  + i + " base " + nextbase);
			if(direction){
				nextbase = nextbase + smallstep;
				temp = store(nextbase);
				currentflaeche = temp.getProfileDistance();
			}
			else{
				nextbase = nextbase - smallstep;
				temp = store(nextbase);
				currentflaeche = temp.getProfileDistance();
			}			
			if(currentflaeche == lastflaeche){
				direction = false;
				//print("b " + nextbase);
			}
			else{
				direction = true;			
			}
			//print("currentflaeche " + currentflaeche);
			if(currentflaeche == lastround){
				//print("reducing stepsize");
				smallstep /= 2;
			}
		}
		return nextBaseItem;
	}	
	
	private PdmOptimization store(double alpha) throws CalculationException{
		PdmOptimization op = new PdmOptimization(dmuList, alpha, urmWeights, optimizationDirections);
		Optimizer.calculatePdm(op);
		StoreItem t = new StoreItem(alpha, op);
		store.add(t);
		return op;
		 
	}
	
	private void fillStore() throws CalculationException{
		
		StoreItem newBase = new StoreItem(0,store(0));
		int a = 1;
		//Util.print("FlaechenLoop "  + a++ + " Flaeche: " + newBase.pdmOptimizationResult.profileDistance);
		while(newBase.pdmOptimization.getProfileDistance() > 0.0000001 && a <100){
		//while(newBase.pdmOptimizationResult.profileDistance > 0.0000001 && a <100){
			newBase = findNextTransition(newBase.pdmOptimization.getProfileDistance(), newBase.alpha);
			//Util.print("FlaechenLoop "  + a++ + " Alpha: " + newBase.pdmOptimization.getAlpha() +  " Flaeche: " + newBase.pdmOptimization.getProfileDistance());
		}
	}
}
